home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / procedural_db.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-11  |  12.1 KB  |  535 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdarg.h>
  22. #include <string.h>
  23.  
  24. #include <glib.h>
  25.  
  26. #include "apptypes.h"
  27.  
  28. #include "appenv.h"
  29. #include "app_procs.h"
  30. #include "plug_in.h"
  31. #include "procedural_db.h"
  32.  
  33. #include "libgimp/gimpparasite.h"
  34.  
  35. #include "libgimp/gimpintl.h"
  36.  
  37.  
  38. GHashTable *procedural_ht = NULL;
  39.  
  40. /*  Local functions  */
  41. static guint   procedural_db_hash_func (gconstpointer key);
  42. static void    pdb_id_init             (void);
  43.  
  44.  
  45. void
  46. procedural_db_init (void)
  47. {
  48.   app_init_update_status (_("Procedural Database"), NULL, -1);
  49.  
  50.   if (!procedural_ht)
  51.     procedural_ht = g_hash_table_new (procedural_db_hash_func, g_str_equal);
  52.   pdb_id_init ();
  53. }
  54.  
  55. static void
  56. procedural_db_free_entry (gpointer key,
  57.               gpointer value,
  58.               gpointer user_data)
  59. {
  60.   if (value)
  61.     g_list_free (value);
  62. }
  63.  
  64. void
  65. procedural_db_free (void)
  66. {
  67.   if (procedural_ht)
  68.     {
  69.       g_hash_table_foreach (procedural_ht, procedural_db_free_entry, NULL);
  70.       g_hash_table_destroy (procedural_ht);
  71.     }
  72.   
  73.   procedural_ht = NULL;
  74. }
  75.  
  76. void
  77. procedural_db_register (ProcRecord *procedure)
  78. {
  79.   GList *list;
  80.  
  81.   if (!procedural_ht)
  82.     procedural_db_init ();
  83.  
  84.   list = g_hash_table_lookup (procedural_ht, (gpointer) procedure->name);
  85.   list = g_list_prepend (list, (gpointer) procedure);
  86.  
  87.   g_hash_table_insert (procedural_ht,
  88.                (gpointer) procedure->name,
  89.                (gpointer) list);
  90. }
  91.  
  92. void
  93. procedural_db_unregister (gchar *name)
  94. {
  95.   GList *list;
  96.  
  97.   list = g_hash_table_lookup (procedural_ht, (gpointer) name);
  98.   if (list)
  99.     {
  100.       list = g_list_remove (list, list->data);
  101.  
  102.       if (list)
  103.     g_hash_table_insert (procedural_ht,
  104.                  (gpointer) name,
  105.                  (gpointer) list);
  106.       else 
  107.     g_hash_table_remove (procedural_ht,
  108.                  (gpointer) name);
  109.     }
  110. }
  111.  
  112. ProcRecord *
  113. procedural_db_lookup (gchar *name)
  114. {
  115.   GList *list;
  116.   ProcRecord *procedure;
  117.  
  118.   list = g_hash_table_lookup (procedural_ht, (gpointer) name);
  119.   if (list != NULL)
  120.     procedure = (ProcRecord *) list->data;
  121.   else
  122.     procedure = NULL;
  123.  
  124.   return procedure;
  125. }
  126.  
  127. Argument *
  128. procedural_db_execute (gchar    *name,
  129.                Argument *args)
  130. {
  131.   ProcRecord *procedure;
  132.   Argument   *return_args;
  133.   GList      *list;
  134.   gint        i;
  135.  
  136.   return_args = NULL;
  137.  
  138.   list = g_hash_table_lookup (procedural_ht, (gpointer) name);
  139.  
  140.   if (list == NULL)
  141.     {
  142.       g_message (_("PDB calling error %s not found"), name);
  143.       
  144.       return_args = g_new (Argument, 1);
  145.       return_args->arg_type = PDB_STATUS;
  146.       return_args->value.pdb_int = PDB_CALLING_ERROR;
  147.       return return_args;
  148.     }
  149.   
  150.   while (list)
  151.     {
  152.       if ((procedure = (ProcRecord *) list->data) == NULL)
  153.     {
  154.       g_message (_("PDB calling error %s not found"), name);
  155.  
  156.       return_args = g_new (Argument, 1);
  157.       return_args->arg_type = PDB_STATUS;
  158.       return_args->value.pdb_int = PDB_CALLING_ERROR;
  159.       return return_args;
  160.     }
  161.       list = list->next;
  162.  
  163.       /*  check the arguments  */
  164.       for (i = 0; i < procedure->num_args; i++)
  165.     {
  166.       if (args[i].arg_type != procedure->args[i].arg_type)
  167.         {
  168.           return_args = g_new (Argument, 1);
  169.           return_args->arg_type = PDB_STATUS;
  170.           return_args->value.pdb_int = PDB_CALLING_ERROR;
  171.  
  172.           g_message (_("PDB calling error %s"), procedure->name);
  173.  
  174.           return return_args;
  175.         }
  176.     }
  177.  
  178.       /*  call the procedure  */
  179.       switch (procedure->proc_type)
  180.     {
  181.     case PDB_INTERNAL:
  182.       return_args = (* procedure->exec_method.internal.marshal_func) (args);
  183.       break;
  184.  
  185.     case PDB_PLUGIN:
  186.       return_args = plug_in_run (procedure, args, procedure->num_args, TRUE, FALSE, -1);
  187.       break;
  188.  
  189.     case PDB_EXTENSION:
  190.       return_args = plug_in_run (procedure, args, procedure->num_args, TRUE, FALSE, -1);
  191.       break;
  192.  
  193.     case PDB_TEMPORARY:
  194.       return_args = plug_in_run (procedure, args, procedure->num_args, TRUE, FALSE, -1);
  195.       break;
  196.  
  197.     default:
  198.       return_args = g_new (Argument, 1);
  199.       return_args->arg_type = PDB_STATUS;
  200.       return_args->value.pdb_int = PDB_EXECUTION_ERROR;
  201.       break;
  202.     }
  203.  
  204.       if ((return_args[0].value.pdb_int != PDB_SUCCESS) &&
  205.       (procedure->num_values > 0))
  206.     memset (&return_args[1], 0, sizeof (Argument) * procedure->num_values);
  207.  
  208.       /*  Check if the return value is a PDB_PASS_THROUGH, in which case run the
  209.        *  next procedure in the list
  210.        */
  211.       if (return_args[0].value.pdb_int != PDB_PASS_THROUGH)
  212.     break;
  213.       else if (list)  /*  Pass through, so destroy return values and run another procedure  */
  214.     procedural_db_destroy_args (return_args, procedure->num_values);
  215.     }
  216.  
  217.   return return_args;
  218. }
  219.  
  220. Argument *
  221. procedural_db_run_proc (gchar *name,
  222.             gint  *nreturn_vals,
  223.             ...)
  224. {
  225.   ProcRecord *proc;
  226.   Argument   *params;
  227.   Argument   *return_vals;
  228.   va_list     args;
  229.   gint        i;
  230.  
  231.   if ((proc = procedural_db_lookup (name)) == NULL)
  232.     {
  233.       return_vals = g_new (Argument, 1);
  234.       return_vals->arg_type      = PDB_STATUS;
  235.       return_vals->value.pdb_int = PDB_CALLING_ERROR;
  236.  
  237.       *nreturn_vals = 1;
  238.       return return_vals;
  239.     }
  240.  
  241.   /*  allocate the parameter array  */
  242.   params = g_new (Argument, proc->num_args);
  243.  
  244.   va_start (args, nreturn_vals);
  245.  
  246.   for (i = 0; i < proc->num_args; i++)
  247.     {
  248.       if (proc->args[i].arg_type != (params[i].arg_type = va_arg (args, PDBArgType)))
  249.     {
  250.       g_message (_("Incorrect arguments passed to procedural_db_run_proc:\n"
  251.                "Argument %d to '%s' should be a %s, but got passed a %s"),
  252.              i+1, proc->name,
  253.              pdb_type_name (proc->args[i].arg_type),
  254.              pdb_type_name (params[i].arg_type));
  255.  
  256.       g_free (params);
  257.  
  258.           *nreturn_vals = 0;
  259.       return NULL;
  260.     }
  261.  
  262.       switch (proc->args[i].arg_type)
  263.     {
  264.     case PDB_INT32:
  265.     case PDB_INT16:
  266.     case PDB_INT8:
  267.         case PDB_DISPLAY:
  268.       params[i].value.pdb_int = (gint32) va_arg (args, int);
  269.       break;
  270.         case PDB_FLOAT:
  271.           params[i].value.pdb_float = (gdouble) va_arg (args, double);
  272.           break;
  273.         case PDB_STRING:
  274.         case PDB_INT32ARRAY:
  275.         case PDB_INT16ARRAY:
  276.         case PDB_INT8ARRAY:
  277.         case PDB_FLOATARRAY:
  278.         case PDB_STRINGARRAY:
  279.         case PDB_COLOR:
  280.           params[i].value.pdb_pointer = va_arg (args, void *);
  281.           break;
  282.         case PDB_REGION:
  283.           break;
  284.         case PDB_IMAGE:
  285.         case PDB_LAYER:
  286.         case PDB_CHANNEL:
  287.         case PDB_DRAWABLE:
  288.         case PDB_SELECTION:
  289.         case PDB_BOUNDARY:
  290.         case PDB_PATH:
  291.       params[i].value.pdb_int = (gint32) va_arg (args, int);
  292.       break;
  293.         case PDB_PARASITE:
  294.           params[i].value.pdb_pointer = va_arg (args, void *);
  295.           break;
  296.         case PDB_STATUS:
  297.       params[i].value.pdb_int = (gint32) va_arg (args, int);
  298.       break;
  299.     case PDB_END:
  300.       break;
  301.     }
  302.     }
  303.  
  304.   va_end (args);
  305.  
  306.   *nreturn_vals = proc->num_values;
  307.  
  308.   return_vals = procedural_db_execute (name, params);
  309.  
  310.   g_free (params);
  311.  
  312.   return return_vals;
  313. }
  314.  
  315. Argument *
  316. procedural_db_return_args (ProcRecord *procedure,
  317.                gboolean    success)
  318. {
  319.   Argument *return_args;
  320.   gint i;
  321.  
  322.   return_args = g_new (Argument, procedure->num_values + 1);
  323.  
  324.   if (success)
  325.     {
  326.       return_args[0].arg_type = PDB_STATUS;
  327.       return_args[0].value.pdb_int = PDB_SUCCESS;
  328.     }
  329.   else
  330.     {
  331.       return_args[0].arg_type = PDB_STATUS;
  332.       return_args[0].value.pdb_int = PDB_EXECUTION_ERROR;
  333.     }
  334.  
  335.   /*  Set the arg types for the return values  */
  336.   for (i = 0; i < procedure->num_values; i++)
  337.     return_args[i+1].arg_type = procedure->values[i].arg_type;
  338.  
  339.   return return_args;
  340. }
  341.  
  342. void
  343. procedural_db_destroy_args (Argument *args,
  344.                 int       nargs)
  345. {
  346.   gint    i, j;
  347.   gint    prev_val = 0;
  348.   gchar **strs;
  349.  
  350.   if (!args)
  351.     return;
  352.  
  353.   for (i = 0; i < nargs; i++)
  354.     {
  355.       switch (args[i].arg_type)
  356.     {
  357.     case PDB_INT32:
  358.       /*  Keep this around in case we need to free an array of strings  */
  359.       prev_val = args[i].value.pdb_int;
  360.       break;
  361.     case PDB_INT16:
  362.     case PDB_INT8:
  363.     case PDB_FLOAT:
  364.       break;
  365.     case PDB_STRING:
  366.     case PDB_INT32ARRAY:
  367.     case PDB_INT16ARRAY:
  368.     case PDB_INT8ARRAY:
  369.     case PDB_FLOATARRAY:
  370.       g_free (args[i].value.pdb_pointer);
  371.       break;
  372.     case PDB_STRINGARRAY:
  373.       strs = (gchar **) args[i].value.pdb_pointer;
  374.       for (j = 0; j < prev_val; j++)
  375.         g_free (strs[j]);
  376.       g_free (strs);
  377.       break;
  378.     case PDB_COLOR:
  379.       g_free (args[i].value.pdb_pointer);
  380.       break;
  381.     case PDB_REGION:
  382.     case PDB_DISPLAY:
  383.     case PDB_IMAGE:
  384.     case PDB_LAYER:
  385.     case PDB_CHANNEL:
  386.     case PDB_DRAWABLE:
  387.     case PDB_SELECTION:
  388.     case PDB_BOUNDARY:
  389.     case PDB_PATH:
  390.     case PDB_PARASITE:
  391.     case PDB_STATUS:
  392.     case PDB_END:
  393.       break;
  394.     }
  395.     }
  396.  
  397.   g_free (args);
  398. }
  399.  
  400. /* We could just use g_str_hash() here ... that uses a different
  401.  * hash function, though
  402.  */
  403.  
  404. static guint
  405. procedural_db_hash_func (gconstpointer key)
  406. {
  407.   const gchar *string;
  408.   guint result;
  409.   int c;
  410.  
  411.   /*
  412.    * I tried a zillion different hash functions and asked many other
  413.    * people for advice.  Many people had their own favorite functions,
  414.    * all different, but no-one had much idea why they were good ones.
  415.    * I chose the one below (multiply by 9 and add new character)
  416.    * because of the following reasons:
  417.    *
  418.    * 1. Multiplying by 10 is perfect for keys that are decimal strings,
  419.    *    and multiplying by 9 is just about as good.
  420.    * 2. Times-9 is (shift-left-3) plus (old).  This means that each
  421.    *    character's bits hang around in the low-order bits of the
  422.    *    hash value for ever, plus they spread fairly rapidly up to
  423.    *    the high-order bits to fill out the hash value.  This seems
  424.    *    works well both for decimal and non-decimal strings.
  425.    *
  426.    * tclHash.c --
  427.    *
  428.    *      Implementation of in-memory hash tables for Tcl and Tcl-based
  429.    *      applications.
  430.    *
  431.    * Copyright (c) 1991-1993 The Regents of the University of California.
  432.    * Copyright (c) 1994 Sun Microsystems, Inc.
  433.    */
  434.  
  435.   string = (const gchar *) key;
  436.   result = 0;
  437.   while (1)
  438.     {
  439.       c = *string;
  440.       string++;
  441.       if (c == 0)
  442.     break;
  443.       result += (result << 3) + c;
  444.     }
  445.  
  446.   return result;
  447. }
  448.  
  449.  
  450. /* The id system's remnants ... */
  451.  
  452.  
  453. static gint next_image_id;
  454. /*
  455. static gint next_drawable_id;
  456. static gint next_display_id;
  457. */
  458.  
  459. static GHashTable *image_hash;
  460. static GHashTable *drawable_hash;
  461. static GHashTable *display_hash;
  462.  
  463. static guint
  464. id_hash_func (gconstpointer id)
  465. {
  466.   return *((guint*) id);
  467. }
  468.  
  469. static gboolean
  470. id_cmp_func (gconstpointer id1,
  471.              gconstpointer id2)
  472. {
  473.   return (*((guint*) id1) == *((guint*) id2));
  474. }
  475.  
  476. static void
  477. add_cb (GimpSet   *set,
  478.         GimpImage *gimage,
  479.     gpointer   data)
  480. {
  481.   guint *id;
  482.  
  483.   id = g_new (guint, 1);
  484.   *id = next_image_id++;
  485.  
  486.   gtk_object_set_data (GTK_OBJECT (gimage), "pdb_id", id);
  487.   g_hash_table_insert (image_hash, id, gimage);
  488. }
  489.  
  490. static void
  491. remove_cb (GimpSet   *set,
  492.            GimpImage *image,
  493.        gpointer   data)
  494. {
  495.   guint *id;
  496.  
  497.   id = (guint *) gtk_object_get_data (GTK_OBJECT (image), "pdb_id");
  498.  
  499.   gtk_object_remove_data (GTK_OBJECT(image), "pdb_id");
  500.   g_hash_table_remove (image_hash, id);
  501.   g_free (id);
  502. }
  503.  
  504. static void
  505. pdb_id_init (void)
  506. {
  507.   image_hash    = g_hash_table_new (id_hash_func, id_cmp_func);
  508.   drawable_hash = g_hash_table_new (id_hash_func, id_cmp_func);
  509.   display_hash  = g_hash_table_new (id_hash_func, id_cmp_func);
  510.  
  511.   gtk_signal_connect (GTK_OBJECT (image_context), "add",
  512.               GTK_SIGNAL_FUNC (add_cb),
  513.               NULL);
  514.   gtk_signal_connect (GTK_OBJECT (image_context), "remove",
  515.               GTK_SIGNAL_FUNC (remove_cb),
  516.               NULL);
  517. }
  518.  
  519.  
  520. gint
  521. pdb_image_to_id (GimpImage *gimage)
  522. {
  523.   guint *id;
  524.  
  525.   id = (guint *) gtk_object_get_data (GTK_OBJECT (gimage), "pdb_id");
  526.  
  527.   return id ? (gint) *id : -1;
  528. }
  529.     
  530. GimpImage *
  531. pdb_id_to_image (gint id)
  532. {
  533.   return g_hash_table_lookup (image_hash, &id);
  534. }
  535.